/*
 * Copyright (c) 2009-2024 Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*============================ INCLUDES ======================================*/

#if defined(_RTE_)
#   include "RTE_Components.h"
#endif

#if defined(RTE_Acceleration_Arm_2D_Helper_PFB)

#include "arm_2d.h"

#ifdef RTE_Acceleration_Arm_2D_Scene0

#define __USER_SCENE0_IMPLEMENT__
#include "arm_2d_scene_0.h"
#include "arm_2d_scenes.h"

#include "arm_2d_helper.h"
#include "arm_2d_example_controls.h"

#include <stdlib.h>
#include <string.h>

#if defined(__clang__)
#   pragma clang diagnostic push
#   pragma clang diagnostic ignored "-Wunknown-warning-option"
#   pragma clang diagnostic ignored "-Wreserved-identifier"
#   pragma clang diagnostic ignored "-Wsign-conversion"
#   pragma clang diagnostic ignored "-Wpadded"
#   pragma clang diagnostic ignored "-Wcast-qual"
#   pragma clang diagnostic ignored "-Wcast-align"
#   pragma clang diagnostic ignored "-Wmissing-field-initializers"
#   pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#   pragma clang diagnostic ignored "-Wmissing-prototypes"
#   pragma clang diagnostic ignored "-Wunused-variable"
#   pragma clang diagnostic ignored "-Wgnu-statement-expression"
#   pragma clang diagnostic ignored "-Wdeclaration-after-statement"
#   pragma clang diagnostic ignored "-Wunused-function"
#   pragma clang diagnostic ignored "-Wmissing-declarations"  
#elif __IS_COMPILER_ARM_COMPILER_5__
#   pragma diag_suppress 64,177
#elif __IS_COMPILER_IAR__
#   pragma diag_suppress=Pa089,Pe188,Pe177,Pe174
#elif __IS_COMPILER_GCC__
#   pragma GCC diagnostic push
#   pragma GCC diagnostic ignored "-Wformat="
#   pragma GCC diagnostic ignored "-Wpedantic"
#   pragma GCC diagnostic ignored "-Wunused-function"
#   pragma GCC diagnostic ignored "-Wunused-variable"
#   pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
#endif

/*============================ MACROS ========================================*/

#if __GLCD_CFG_COLOUR_DEPTH__ == 8

#   define c_tileCMSISLogo          c_tileCMSISLogoGRAY8

#elif __GLCD_CFG_COLOUR_DEPTH__ == 16

#   define c_tileCMSISLogo          c_tileCMSISLogoRGB565

#elif __GLCD_CFG_COLOUR_DEPTH__ == 32

#   define c_tileCMSISLogo          c_tileCMSISLogoCCCA8888
#else
#   error Unsupported colour depth!
#endif

/*============================ MACROFIED FUNCTIONS ===========================*/
#undef this
#define this (*ptThis)

/*============================ TYPES =========================================*/
/*============================ GLOBAL VARIABLES ==============================*/

extern const arm_2d_tile_t c_tileCMSISLogo;
extern const arm_2d_tile_t c_tileCMSISLogoMask;
extern const arm_2d_tile_t c_tileCMSISLogoA2Mask;
extern const arm_2d_tile_t c_tileCMSISLogoA4Mask;
extern uint16_t key_num ;
void snake_init();
void snake_move();
void snake_run();
void snake_level_run();
uint16_t get_snake_level_time();
void draw_my_snake(void *pTarget,                                  
                 const arm_2d_tile_t *ptTile,                   
                 bool bIsNewFrame);
								 
/*============================ PROTOTYPES ====================================*/
/*============================ LOCAL VARIABLES ===============================*/

/*! define dirty regions */
IMPL_ARM_2D_REGION_LIST(s_tDirtyRegions, static)

    /* a dirty region to be specified at runtime*/
    ADD_REGION_TO_LIST(s_tDirtyRegions,
        0  /* initialize at runtime later */
    ),
    
    /* add the last region:
        * it is the top left corner for text display 
        */
    ADD_LAST_REGION_TO_LIST(s_tDirtyRegions,
        .tLocation = {
            .iX = 0,
            .iY = 0,
        },
        .tSize = {
            .iWidth = 320,
            .iHeight = 240,
        },
    ),

END_IMPL_ARM_2D_REGION_LIST(s_tDirtyRegions)

/*============================ IMPLEMENTATION ================================*/

static void __on_scene0_load(arm_2d_scene_t *ptScene)
{
    user_scene_0_t *ptThis = (user_scene_0_t *)ptScene;
    ARM_2D_UNUSED(ptThis);

}

static void __on_scene0_depose(arm_2d_scene_t *ptScene)
{
    user_scene_0_t *ptThis = (user_scene_0_t *)ptScene;
    ARM_2D_UNUSED(ptThis);
    
    ptScene->ptPlayer = NULL;
    
    /* reset timestamp */
    arm_foreach(int64_t,this.lTimestamp, ptItem) {
        *ptItem = 0;
    }

    if (!this.bUserAllocated) {
        __arm_2d_free_scratch_memory(ARM_2D_MEM_TYPE_UNSPECIFIED, ptScene);
    }
}

/*----------------------------------------------------------------------------*
 * Scene 0                                                                    *
 *----------------------------------------------------------------------------*/

static void __on_scene0_background_start(arm_2d_scene_t *ptScene)
{
    user_scene_0_t *ptThis = (user_scene_0_t *)ptScene;
    ARM_2D_UNUSED(ptThis);

}

static void __on_scene0_background_complete(arm_2d_scene_t *ptScene)
{
    user_scene_0_t *ptThis = (user_scene_0_t *)ptScene;
    ARM_2D_UNUSED(ptThis);

}


static void __on_scene0_frame_start(arm_2d_scene_t *ptScene)
{
    user_scene_0_t *ptThis = (user_scene_0_t *)ptScene;
    ARM_2D_UNUSED(ptThis);
	 //
	uint16_t delay_time = get_snake_level_time();
	snake_run();
	if (arm_2d_helper_is_time_out(delay_time, &this.lTimestamp[0])) {
        snake_level_run();//snake_move();//arm_2d_scene_player_switch_to_next_scene(ptScene->ptPlayer);
    }

}
static char go_back_flag = 0;
static void __on_scene0_frame_complete(arm_2d_scene_t *ptScene)
{
    user_scene_0_t *ptThis = (user_scene_0_t *)ptScene;
    ARM_2D_UNUSED(ptThis);
    
    /* switch to next scene after 3s */
		if(go_back_flag){
					go_back_flag = 0;
					__arm_2d_scene1_init(   &DISP0_ADAPTER ,NULL);
					arm_2d_scene_player_switch_to_next_scene(ptScene->ptPlayer);
		}
    
}

static void __before_scene0_switching_out(arm_2d_scene_t *ptScene)
{
    user_scene_0_t *ptThis = (user_scene_0_t *)ptScene;
    ARM_2D_UNUSED(ptThis);

}

static
IMPL_PFB_ON_DRAW(__pfb_draw_scene0_handler)
{
    user_scene_0_t *ptThis = (user_scene_0_t *)pTarget;
    arm_2d_size_t tScreenSize = ptTile->tRegion.tSize;

    ARM_2D_UNUSED(ptTile);
    ARM_2D_UNUSED(bIsNewFrame);
    ARM_2D_UNUSED(tScreenSize);
    
    arm_2d_canvas(ptTile, __top_canvas) {
    /*-----------------------draw the foreground begin-----------------------*/
        
        /* following code is just a demo, you can remove them */
        
        arm_2d_fill_colour(ptTile, NULL, GLCD_COLOR_WHITE);
			
			//arm_2d_fill_colour(ptTile, NULL, GLCD_COLOR_WHITE);

        
						draw_my_snake(pTarget,  ptTile, bIsNewFrame);
				

        


    

        /* draw text at the top-left corner */

        arm_lcd_text_set_target_framebuffer((arm_2d_tile_t *)ptTile);
        arm_lcd_text_set_font(&ARM_2D_FONT_6x8.use_as__arm_2d_font_t);
        arm_lcd_text_set_draw_region(NULL);
        arm_lcd_text_set_colour(GLCD_COLOR_RED, GLCD_COLOR_WHITE);
        arm_lcd_text_location(0,0);
        //arm_lcd_puts("Scene 0");
				arm_lcd_printf("Scene %d=%d",key_num,4);

    /*-----------------------draw the foreground end  -----------------------*/
    }
    arm_2d_op_wait_async(NULL);

    return arm_fsm_rt_cpl;
}

ARM_NONNULL(1)
user_scene_0_t *__arm_2d_scene0_init(   arm_2d_scene_player_t *ptDispAdapter, 
                                        user_scene_0_t *ptThis)
{
    bool bUserAllocated = false;
    assert(NULL != ptDispAdapter);

    s_tDirtyRegions[dimof(s_tDirtyRegions)-1].ptNext = NULL;

    /* get the screen region */
    arm_2d_region_t tScreen
        = arm_2d_helper_pfb_get_display_area(
            &ptDispAdapter->use_as__arm_2d_helper_pfb_t);

    /* initialise dirty region 0 at runtime
     * this demo shows that we create a region in the centre of a screen(320*240)
     * for a image stored in the tile c_tileCMSISLogoMask
     */
    arm_2d_align_centre(tScreen, c_tileCMSISLogoMask.tRegion.tSize) {
        //s_tDirtyRegions[0].tRegion = __centre_region;
    }

    //s_tDirtyRegions[dimof(s_tDirtyRegions)-1].tRegion.tSize.iWidth 
    //                                                    = tScreen.tSize.iWidth;
    
    if (NULL == ptThis) {
        ptThis = (user_scene_0_t *)
                    __arm_2d_allocate_scratch_memory(   sizeof(user_scene_0_t),
                                                        __alignof__(user_scene_0_t),
                                                        ARM_2D_MEM_TYPE_UNSPECIFIED);
        assert(NULL != ptThis);
        if (NULL == ptThis) {
            return NULL;
        }
    } else {
        bUserAllocated = true;
    }
    memset(ptThis, 0, sizeof(user_scene_0_t));

    *ptThis = (user_scene_0_t){
        .use_as__arm_2d_scene_t = {

            /* the canvas colour */
            .tCanvas = {GLCD_COLOR_WHITE}, 

            /* Please uncommon the callbacks if you need them
             */
            .fnOnLoad       = &__on_scene0_load,
            .fnScene        = &__pfb_draw_scene0_handler,
            .ptDirtyRegion  = (arm_2d_region_list_item_t *)s_tDirtyRegions,
            

            //.fnOnBGStart    = &__on_scene0_background_start,
            //.fnOnBGComplete = &__on_scene0_background_complete,
            .fnOnFrameStart = &__on_scene0_frame_start,
            //.fnBeforeSwitchOut = &__before_scene0_switching_out,
            .fnOnFrameCPL   = &__on_scene0_frame_complete,
            .fnDepose       = &__on_scene0_depose,

            .bUseDirtyRegionHelper = false,
        },
        .bUserAllocated = bUserAllocated,
    };

    /* ------------   initialize members of user_scene_0_t begin ---------------*/


    /* ------------   initialize members of user_scene_0_t end   ---------------*/

    arm_2d_scene_player_append_scenes(  ptDispAdapter, 
                                        &this.use_as__arm_2d_scene_t, 
                                        1);
																				
    snake_init();
    return ptThis;
}


//======================================================	
#define SNAKE_BODY_ALL_LEN 100

char eat_food_flag = 0;
typedef struct snake_body{
		int16_t iX;
		int16_t iY;
		uint16_t color;
}snake_body_t;
static struct {
		snake_body_t my_snake_body[SNAKE_BODY_ALL_LEN];
		uint16_t snake_body_len;
		uint16_t snake_body_width;
		uint16_t snake_speed;
		uint16_t level_time;
		char direction;//left,right,up,down
		char crash_into_a_wall_flag;
		char suspend_flag;
	  uint32_t my_ramd_num ;
		uint32_t my_ramd_num2;
		
		
}my_eat_snake;

static struct {
		snake_body_t food;		
		uint16_t width;		
}my_snake_food;
snake_body_t food_vidio;

uint16_t get_snake_level_time(){
		return my_eat_snake.level_time;
}
void snake_init(){
		uint16_t i ;
		for(i = 0; i < SNAKE_BODY_ALL_LEN; i++){
				my_eat_snake.my_snake_body[i].color = GLCD_COLOR_BLUE;
		}
		my_eat_snake.snake_body_len = 3;
		my_eat_snake.snake_body_width = 10;
		my_eat_snake.direction = 0;
		my_eat_snake.crash_into_a_wall_flag = 0;
		my_eat_snake.level_time = 500;
		my_eat_snake.suspend_flag = 0;
	
		my_eat_snake.my_snake_body[0].iX = 70;
		my_eat_snake.my_snake_body[0].iY = 40;
	
		my_eat_snake.my_snake_body[1].iX = 60;
		my_eat_snake.my_snake_body[1].iY = 40;
	
		my_eat_snake.my_snake_body[2].iX = 50;
		my_eat_snake.my_snake_body[2].iY = 40;
		
		my_snake_food.food.iX  = 50;
		my_snake_food.food.iY  = 50;
		my_snake_food.food.color = GLCD_COLOR_RED;
		my_snake_food.width = 10;
		
		
}
void draw_snake_food(){
		//LCD_draw_block(my_snake_food.food.iX,my_snake_food.food.iY,my_snake_food.width,my_snake_food.width,my_snake_food.food.color);
}

void draw_snake(){
		uint16_t i;
		//LCD_1IN3_Clear(GLCD_COLOR_BLACK);
		for(i = 0; i < my_eat_snake.snake_body_len; i++){
				//LCD_draw_block(my_eat_snake.my_snake_body[i].iX ,my_eat_snake.my_snake_body[i].iY,my_eat_snake.snake_body_width,my_eat_snake.snake_body_width,my_eat_snake.my_snake_body[i].color);
		}
}
void snake_add_level(){
		my_eat_snake.level_time = 500 - 50*(my_eat_snake.snake_body_len /10) ;
		
}
void snake_eat_food(){
	  static char time = 0;
		if(my_eat_snake.my_snake_body[0].iX == my_snake_food.food.iX){
				if(my_eat_snake.my_snake_body[0].iY == my_snake_food.food.iY){
						eat_food_flag = 1; 
				    my_eat_snake.snake_body_len += 1;
						my_eat_snake.my_snake_body[my_eat_snake.snake_body_len - 1].iX = my_eat_snake.my_snake_body[my_eat_snake.snake_body_len - 2].iX;
						my_eat_snake.my_snake_body[my_eat_snake.snake_body_len - 1].iY = my_eat_snake.my_snake_body[my_eat_snake.snake_body_len - 2].iY;
					
						food_vidio = my_snake_food.food;
						my_snake_food.food.iX = my_snake_food.width * (my_eat_snake.my_ramd_num  % 32);
						my_snake_food.food.iY = my_snake_food.width * (my_eat_snake.my_ramd_num2 % 24);
					//snake_move();
					  snake_add_level();
		
				}
		}
		if(eat_food_flag){
				time++;
				if(time >= 3){
						time = 0;
						eat_food_flag = 0; 
				}
		}
}
void snake_move(){
		uint16_t i;
		for( i = my_eat_snake.snake_body_len - 1; i > 0; i--){
				my_eat_snake.my_snake_body[i].iX = my_eat_snake.my_snake_body[i-1].iX;
				my_eat_snake.my_snake_body[i].iY = my_eat_snake.my_snake_body[i-1].iY;
			
				
		}
		if(my_eat_snake.direction == 1){  //left
				my_eat_snake.my_snake_body[0].iX -= my_eat_snake.snake_body_width;
				my_eat_snake.my_snake_body[0].iY += 0;
		}else if(my_eat_snake.direction == 2){  //up
				my_eat_snake.my_snake_body[0].iX += 0;
				my_eat_snake.my_snake_body[0].iY -= my_eat_snake.snake_body_width;
		}else if(my_eat_snake.direction == 3){  //down
				my_eat_snake.my_snake_body[0].iX += 0;
				my_eat_snake.my_snake_body[0].iY += my_eat_snake.snake_body_width;
		}else{//right
				my_eat_snake.my_snake_body[0].iX += my_eat_snake.snake_body_width;
				my_eat_snake.my_snake_body[0].iY += 0;
		}
		
		
}

void snake_Crash_into_a_wall(){
		if(my_eat_snake.direction == 1){ //left
			 if(my_eat_snake.my_snake_body[0].iX < 0){
				   my_eat_snake.crash_into_a_wall_flag  = 1;
			 }
			
		}
		else if(my_eat_snake.direction == 2){  //up
			  if(my_eat_snake.my_snake_body[0].iY < 0){
				   my_eat_snake.crash_into_a_wall_flag  = 1;
			 }
		}else if(my_eat_snake.direction == 3){  //down
			  if(my_eat_snake.my_snake_body[0].iY >= 240){
				   my_eat_snake.crash_into_a_wall_flag  = 1;
			 }
		}else{
		    if(my_eat_snake.my_snake_body[0].iX >= 320){
				   my_eat_snake.crash_into_a_wall_flag  = 1;
			 }
		}
}

void snake_level_run(){
	  if(my_eat_snake.suspend_flag == 0){
				if(0 == my_eat_snake.crash_into_a_wall_flag){
						snake_move();
				}
		}
		snake_eat_food();
		snake_Crash_into_a_wall();
		
}

void set_snake_direction(char i){
		my_eat_snake.direction = i;
}

void snake_key_board(){
		switch(key_num){
			case 1:
				case 4:
					case 7:
						//case 10:
				set_snake_direction(1);//left
			break;
			//case 14:
			case 2:
					case 3:
						case 5:
							case 6:
				set_snake_direction(2);//up
			break;
			case 8:
				case 9:
					case 11:
						case 12:
				set_snake_direction(3);//down
			break;
			case 17:
				case 18:
					case 19:
						//case 20:
				set_snake_direction(4);//right
			break;
			case 16://暂停
					my_eat_snake.suspend_flag = 1;
			break;
			case 15://停止暂停
					my_eat_snake.suspend_flag = 0;
			break;	
			case 13://重新开始
					if(my_eat_snake.crash_into_a_wall_flag){
							my_eat_snake.crash_into_a_wall_flag = 0;
							snake_init();
							key_num = 0;
					}
			break;	
			case 14://返回主页
					 go_back_flag = 1;
			break;
				
		}
		key_num = 0;
}

void snake_run(){
		my_eat_snake.my_ramd_num++;
		my_eat_snake.my_ramd_num2 += 7;
		snake_key_board();
		//snake_move();	
		//draw_snake();
		//draw_snake_food();					
		//DEV_Delay_ms(1000);							
}

void draw_my_snake(void *pTarget,                                  
                 const arm_2d_tile_t *ptTile,                   
                 bool bIsNewFrame){
		arm_2d_region_t myRegion;
		uint16_t i;							 
		myRegion.tLocation.iX = 10;
		myRegion.tLocation.iY	 = 20;
		myRegion.tSize.iHeight = 10;
		myRegion.tSize.iWidth = 10;	
									 
									 
		
		
		for(i = 0; i < my_eat_snake.snake_body_len; i++){
				myRegion.tLocation.iX = my_eat_snake.my_snake_body[i].iX;
				myRegion.tLocation.iY	 = my_eat_snake.my_snake_body[i].iY;
				draw_round_corner_box(  ptTile, 
														&myRegion, 
														GLCD_COLOR_BLACK, 
														255,
														bIsNewFrame);
			
				//LCD_draw_block(my_eat_snake.my_snake_body[i].iX ,my_eat_snake.my_snake_body[i].iY,my_eat_snake.snake_body_width,my_eat_snake.snake_body_width,my_eat_snake.my_snake_body[i].color);
		}							 
		myRegion.tLocation.iX = my_snake_food.food.iX;
		myRegion.tLocation.iY	 = my_snake_food.food.iY;	
		draw_round_corner_border(   ptTile, 
                                        &myRegion, 
                                        GLCD_COLOR_RED, 
                                        (arm_2d_border_opacity_t)
                                            {32, 32, 255-64, 255-64},
                                        (arm_2d_corner_opacity_t)
                                            {128, 128, 128, 128});	
		if(eat_food_flag){
			
				myRegion.tLocation.iX = food_vidio.iX - 10;
				myRegion.tLocation.iY	 = food_vidio.iY;
				myRegion.tSize.iHeight = 5;
				myRegion.tSize.iWidth = 5;
				draw_round_corner_box(  ptTile, 
														&myRegion, 
														GLCD_COLOR_GREEN, 
														255,
														bIsNewFrame);
			
			myRegion.tLocation.iX = food_vidio.iX + 10;
			myRegion.tLocation.iY	 = food_vidio.iY;
			draw_round_corner_box(  ptTile, 
														&myRegion, 
														GLCD_COLOR_GREEN, 
														255,
														bIsNewFrame);
			
			myRegion.tLocation.iX = food_vidio.iX ;
			myRegion.tLocation.iY	 = food_vidio.iY-10;
			draw_round_corner_box(  ptTile, 
														&myRegion, 
														GLCD_COLOR_GREEN, 
														255,
														bIsNewFrame);
			myRegion.tLocation.iX = food_vidio.iX ;
			myRegion.tLocation.iY	 = food_vidio.iY+10;
			draw_round_corner_box(  ptTile, 
														&myRegion, 
														GLCD_COLOR_GREEN, 
														255,
														bIsNewFrame);											
		
		}		
		do{
				arm_lcd_text_set_target_framebuffer((arm_2d_tile_t *)ptTile);
						arm_lcd_text_set_font(&ARM_2D_FONT_16x24.use_as__arm_2d_font_t);
						arm_lcd_text_set_draw_region(NULL);
					if(my_eat_snake.suspend_flag){
							arm_lcd_text_set_colour(GLCD_COLOR_GREEN, GLCD_COLOR_WHITE);
							arm_lcd_text_location(4,6);
							
							arm_lcd_printf("Suspend!");
					}
					if(my_eat_snake.crash_into_a_wall_flag){
						
						arm_lcd_text_set_colour(GLCD_COLOR_RED, GLCD_COLOR_WHITE);
						arm_lcd_text_location(3,4);
						
						arm_lcd_printf("Game Over!!");
					}
		}while(0);
		      
                                    
       
}
								 


#if defined(__clang__)
#   pragma clang diagnostic pop
#endif

#endif

#endif

